home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Information / CSMP Digest / volume 2 / csmp-v2-016.txt < prev    next >
Text File  |  1995-06-30  |  50KB  |  1,529 lines

  1. C.S.M.P. Digest             Wed, 24 Feb 93       Volume 2 : Issue 16
  2.  
  3. Today's Topics:
  4.  
  5.     Hiliting with the hilight color??? Problem
  6.     'aete' TMPL wanted
  7.     Verifying valid handles, how to?
  8.     Memory allocation in your app
  9.  
  10.  
  11.  
  12. The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
  13.  
  14. The digest is a collection of article threads from the usenet newsgroup
  15. comp.sys.mac.programmer.  It is designed for people who read c.s.m.p. semi-
  16. regularly and want an archive of the discussions.  If you don't know what a
  17. newsgroup is, you probably don't have access to it.  Ask your systems
  18. administrator(s) for details.  If you don't have access to news, you can
  19. post articles to any newsgroup by mailing your article to
  20.     newsgroup@cs.utexas.edu
  21. So, to post an article to comp.sys.mac.programmer, mail your article to
  22.     comp-sys-mac-programmer@cs.utexas.edu
  23. Note the '-' instead of '.' in the newsgroup name.  Be sure to ask that
  24. replies be emailed to you instead of posted to the group, and give your
  25. email address.
  26.  
  27. Each issue of the digest contains one or more sets of articles (called
  28. threads), with each set corresponding to a 'discussion' of a particular
  29. subject.  The articles are not edited; all articles included in this digest
  30. are in their original posted form (as received by our news server at
  31. cs.uoregon.edu).  Article threads are not added to the digest until the last
  32. article added to the thread is at least one month old (this is to ensure that
  33. the thread is dead before adding it to the digest).  Article threads that
  34. consist of only one message are generally not included in the digest.
  35.  
  36. The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
  37. [128.223.8.8] in the directory /pub/mac/csmp-digest.  Be sure to read the
  38. file /pub/mac/csmp-digest/README before downloading any files.  The most
  39. recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
  40. directory /info-mac/digest/csmp.  If you don't have ftp capability, the sumex
  41. archive has a mail server; send a message with the text '$MACarch help' (no
  42. quotes) to LISTSERV@ricevm1.rice.edu for more information.
  43.  
  44. The digest is also available via email.  Just send a note saying that you
  45. want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
  46. automatically receive each new issue as it is created.  Sorry, back issues
  47. are not available through the mailing list.
  48.  
  49. Send administrative mail to mkelly@cs.uoregon.edu.
  50.  
  51.  
  52. -------------------------------------------------------
  53.  
  54. From: pcw@access.digex.com (Peter Wayner)
  55. Subject: Hiliting with the hilight color??? Problem
  56. Date: 21 Jan 93 14:36:01 GMT
  57. Organization: Express Access Online Communications, Greenbelt MD USA
  58.  
  59. I've been having problems with hilighting some text using
  60. the hilighting color. If I use the InvertRect command without
  61. doing anything, then it is possible to toggle between regular
  62. black on white text and inverted white on black text with
  63. a single call to InvertRect. 
  64.  
  65. If I clear the top bit of the right part of the toolbox memory,
  66. then I get a perfect result the first time I call InvertRect.
  67. The text goes from black on white to black on hilight color. But
  68. on the second call when I try to revert the text to normal, it turns
  69. black. 
  70.  
  71. What's the trick? Why isn't it toggling?
  72.  
  73. Any help would be much apprciated. Thanks....
  74.  
  75. Peter Wayner
  76. (pcw@access.digex.com)
  77.  
  78. +++++++++++++++++++++++++++
  79.  
  80. From: absurd@apple.apple.com (Tim Dierks, software saboteur)
  81. Date: 21 Jan 93 16:12:49 GMT
  82. Organization: MacDTS Marauders
  83.  
  84. In article <pcw.727626961@digex>, pcw@access.digex.com (Peter Wayner)
  85. wrote:
  86. > I've been having problems with hilighting some text using
  87. > the hilighting color. If I use the InvertRect command without
  88. > doing anything, then it is possible to toggle between regular
  89. > black on white text and inverted white on black text with
  90. > a single call to InvertRect. 
  91. > If I clear the top bit of the right part of the toolbox memory,
  92. > then I get a perfect result the first time I call InvertRect.
  93. > The text goes from black on white to black on hilight color. But
  94. > on the second call when I try to revert the text to normal, it turns
  95. > black. 
  96. > What's the trick? Why isn't it toggling?
  97. > Any help would be much apprciated. Thanks....
  98. > Peter Wayner
  99. > (pcw@access.digex.com)
  100.  
  101. If you're using the HiliteMode low memory global, you need to turn it
  102. on before each and every invert call you make; it will turn itself off.
  103. In essence, it's just a flag to say "Make the next invert call hilite".
  104. If you want a more permanent solution (also good because it doesn't use
  105. low memory globals), just use the hilite transfer mode; it will do
  106. the hiliting for you and it won't turn off.
  107.  
  108. Tim Dierks
  109. MacDTS, but I speak for myself
  110.  
  111. +++++++++++++++++++++++++++
  112.  
  113. From: rick@akbar.cc.utexas.edu (Rick Watson)
  114. Date: 23 Jan 1993 03:17:16 GMT
  115. Organization: University of Texas at Austin
  116.  
  117. >If I clear the top bit of the right part of the toolbox memory,
  118. >then I get a perfect result the first time I call InvertRect.
  119. >The text goes from black on white to black on hilight color. But
  120. >on the second call when I try to revert the text to normal, it turns
  121. >black. 
  122.  
  123. Did you remember to do the BitClr((Ptr)HiliteMode,pHiliteBit);
  124. before each InvertRect? Quickdraw resets the bit after 
  125. various calls. This is documented somewhere in the vicinity
  126. of the description of pHiliteBit.
  127.  
  128. Rick Watson 
  129. The University of Texas Computation Center, Networking Services, 512/471-3241
  130.    internet: r.watson@utexas.edu             bitnet: watson@utadnx
  131.    uucp:     ...!cs.utexas.edu!ut-emx!rick   span:   utspan::utadnx::watson
  132.  
  133. ---------------------------
  134.  
  135. From: povlphp@uts.uni-c.dk (Povl H. Pedersen)
  136. Subject: 'aete' TMPL wanted
  137. Organization: UNI-C, Danish Computing Centre for Research and Education
  138. Date: Wed, 20 Jan 1993 18:40:06 GMT
  139.  
  140. Subject says it all. Please mail me an aete TNPL if you have one.
  141. I am going to start doing some AE stuff.
  142. - -- 
  143. Povl H. Pedersen   -   Macintosh specialist. Knows some DOS and UNIX too.
  144. pope@imv.aau.dk    -   povlphp@uts.uni-c.dk
  145.  
  146. +++++++++++++++++++++++++++
  147.  
  148. From: ross@bnr.ca (Ross Brown)
  149. Organization: Bell-Northern Research Ltd.
  150. Date: Wed, 20 Jan 1993 19:33:27 GMT
  151.  
  152. In article <1993Jan20.184006.15422@uts.uni-c.dk> povlphp@uts.uni-c.dk (Povl H.
  153. Pedersen) writes:
  154. >Subject says it all. Please mail me an aete TNPL if you have one.
  155. >I am going to start doing some AE stuff.
  156. >-- 
  157. >Povl H. Pedersen   -   Macintosh specialist. Knows some DOS and UNIX too.
  158. >pope@imv.aau.dk    -   povlphp@uts.uni-c.dk
  159. >
  160.  
  161. Here is the template.  It's not useful most of the time, because 'aete'
  162. resources are too big for ResEdit to display using a template.  I have also
  163. included a stuffed version of the Rez types file, which is more useful.
  164.  
  165. (This file must be converted with BinHex 4.0)
  166.  
  167. :"'&PG'8!FR0bBe*6483!N!J*Z%+E!*!%!3#3!`Q"!!!)J3#3!cF!!%0K$P*PB@3
  168. J6@8J,5!b9f&jC3)!N!0849K8G(4iG!4KCA4PJ3)!N!0bFh*M8P0&4!#3#PDr!*!
  169. %FR0bBe*6483!N"LRJa"-!*!'#EJ!N!`I!*!$3f%C9(*TB@`J9A0PFLGc)%GeD@4
  170. P)#dJ-PGKH3)!N!0849K8G(4iG!%!!$3!N!C*!`#3"$rN!!"#!*!&!D`!!!B!T[I
  171. M#DEr&@)!N"D0U3!,!*!+#(d@9'9YF'aKG'8J6@&UEh)J9Q9bFfP[ENK#@93@9'9
  172. YF'aKG'8J6@PZEh)J9Q9bFfP[ENK#@94!6'&ZCh9KCf8J583J,5"cD'peE'3JBQ8
  173. JFf&YC5"KFb"dD'Pc)(*PFfpeFQ0P)%P%)#dJ-#"QEh)J4@jRE'PcD%4A8N3,8f0
  174. bDA"d)%0[C'9%9e*%#e0eDA4PFb"XDA0d6d019!8UN!9-8e4$#P0eDA4P)%jKE@9
  175. 38e45"f0[E@ePER438e45"5U3"8&A8N3+8h9TG'8J3fpNC94138d,8h9TG'8J6'9
  176. fC@a%9e*%$90eDA4P)&CPFR0TEfj%9e*%#eP[GA)J4ACPER4c6d019!8UN!9-8e4
  177. $#89fC@jd6Q&YC9"69&)(BfpYE@9ZG&"69&)&+T!&39G54!p&GQ9ZG%0XBA0c)'0
  178. [C'986N&0$%9fC@jd583JBfpNC94138dF8Q9`E(NJ9(P`C5`JEh)JER9XE#"QEh)
  179. JEQpZC94138d08Q9`E(NJBfpYE@9ZG&"69&)&+T!&39G54"&5CA"XH5"TFb"2F(4
  180. TEfjKE%*#593C3f&Z)'*P)'%JD'pYEfGPEQ9[GA-JE'PcG%*#59355A-J4@jeE@9
  181. bBA4PC#"dHA"P3N**9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9
  182. N3N**9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0
  183. PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593
  184. )FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593H4'PbC@0d)&"
  185. KFQ&YCA4PFL"`FQ9QCA*PC#"dHA"P9%j"64K%DA*PBh3J8'&bB@ePG'9b)'0[E@e
  186. PER438e45"5U3"8&A8N394'PbC@0d)&"KFQ&Y)%p`G'P[EQ&X3N**9"P$B@iJBQ8
  187. JB5"SEfe[Cf9ZC@peFb"XDA0d3N**9"**Fb"&ER9YCA*KG'9N)(4jF'9#3NP8$%0
  188. SB@jRC5"6G'&dC8*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRC
  189. PC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593)FQ9
  190. cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP
  191. 8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#594I6h4SCA)J8'&bB@ePG'9bFbiJ)%j
  192. [G'8JG'KKG#"[FQ4PFL"TFb"cD@GZD@CTBf&ZG#`JGfKPEL"`BA*KE@9dCA*c)'&
  193. bC5"XDA0dC@3JGfPdD'peG#"VCAPhEh*NFbj23dj8"5U3"8a69%-18'&bB@ePG'9
  194. b)%jKE@938e45"5U3"8&A8N318'&bB@ePG'9b)%0[C'986N&0$P"KFQ&YCA4PFL"
  195. dHA"P9%j"64&3BA*KE@9dCA)JBfpYE@9ZG&"69&)&+T!&39G54!YTCL"[F(4TEfj
  196. KE%*#593C3f&Z)'*P)'%JD'pYEfGPEQ9[GA-JE'PcG%*#59355A-J4@jeE@9bBA4
  197. PC#"dHA"P3N**9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N*
  198. *9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRC
  199. PC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593)FQ9
  200. cCA*fC@4#3NP8#(*PFf9bGQ9N3N**9!KbCA0PFRCPC%*#593&+T!&6&08438UN!9
  201. - -8e4&"d0XBA0cCA023dj8"5U3"8a69%-+3faKFh-J6Q&YC9"69&)&+T!&39G54!T
  202. $E'&cFb"$Ef4P9%j"63GMEfeYC@jd8&088J8UN!9"9e*%#P"bEh"PFR4TCA023dj
  203. 8"5U3"8a69%-*8(*[F#"1B@eP8&088J8UN!9"9e*%#9"bEh!J3fpNC94138d+8(*
  204. [F#"$E'&cFe4138d(BfpYE@9ZG&"69&)&+T!&39G54!KbCA0PFRCPC%*#593C3f&
  205. Z)'*P)'%JD'pYEfGPEQ9[GA-JE'PcG%*#59355A-J4@jeE@9bBA4PC#"dHA"P3N*
  206. *9!T5C@&N,eGbDA4P3N**9!KbCA0PFRCPC%*#593)FQ9cCA*fC@4#3NP8#(*PFf9
  207. bGQ9N3N**9!KbCA0PFRCPC%*#593&+T!&4N*C9!8UN!9-8e4&#%9XC@ePER4c6d0
  208. 19!8UN!9-8e4$%N9XC@ePER3J3faKFh-J3fpNC94138d*5f9j)%C[FQec6d019!8
  209. UN!9-8e4$#8C[FQdJ3fpNC94138d&+T!&6&08438UN!9-8e4&"5U3"8a69%883fp
  210. YF'&bDA0[EL"2F'9bBA4[FR023dj8"5U3"8a69%-%EQ&YC9"69&)&+T!&39G54!4
  211. MEf4P9%j"63GMEfeYC@jd8&088J8UN!9"9e*%"5U3"8a69%8*3fpZFh4KER4c6d0
  212. 19!8UN!9-8e4$$89ZG@ePFQ&dEh)J58486N&0#d9ZG@ePFQ&dEh*c6d019!8UN!9
  213. - -8e4$$d9ZG@ePFQ&dEh)J6Q&YC9"69&)&+T!&39G54!e&ER9YCA*KG'pb)%P%9%j
  214. "64*&ER9YCA*KG'pb)%0[E@ePER438e45"5U3"8&A8N3&+T!&6&08438UN!9-8e4
  215. &"5U3"8a69%8!!!%!N!-*J3!!#)%!N!-h!#bI,!pZ!*!$(!!b!!"869"-!*!$#J#
  216. !!*!(,*lX"'&PG'83RJ:
  217.  
  218. (This file must be converted with BinHex 4.0)
  219.  
  220. :#'&PG'8ZFfPd!&0*9%46593K!*!%#1J!!!&'#h96593K!!%!!!MSFNaKG3+`!*!
  221. $&J!i$3d43899Ff9b9'9bE94jF'9c,R*%!*!0piN!N"VrN!4849K869"6)!!!TD'
  222. `'k@KX"X!!!`#!!!bK3!!!dd!!!89RdJN!*!(Jj`d"%%5"&(R9)+)`XT'BPAV0"Y
  223. 3RTqcGlrXq2`#JYMeMXh-m1U#TZdE*2BB@'SXb65@M-SF9f`XM5qK8(**Mb'CrG)
  224. bQL)8a5,iJG(lIHhXbcFML2D(%%3d9CT8RPHA*DQ4kFE5(L2bb`ML`)HUX951kFS
  225. Xb5l&A'jjR%Gm5*UD%M%UIj3a2VX03B`reiba'0Cp@95c2YQ&`pTYAaBrXT!!)2E
  226. G%K!f%Ek*B2dX5DR9Yl``"rhFZ`q,-+*@``dcMD1+#l,,M%d('8Y+miX+QlC-f#B
  227. qHA"kXU&[GQ&HHADHX@R[j+CYQTD1,#S['0&dZ,&TDIBSBp2XdUCP)r0,QjBB5i[
  228. +5h,-)[P0FiY+Q[BSc#[),ah*QNM0+-m[-jBf4AaprqkTQE9DXGrmM-cZ84c66%8
  229. c&4QCkC%j4D0''3[,@-bLcLiDBFa-6Hc(Hc$l'NFE#eK23hMFbSZl["Bc-(Z-4[e
  230. eRlT-i8Mp*Y-jjZb#l0,5TMPQTck13dP+3PDkXEKJA&0ffLFfa@6AP"F8F"'[+5V
  231. N"%BRjjFBFmUDTQ@AS-IeaT+Qa5A'A'1*F866-K5&41ER%Y%8KR3IL90'!l+i$'H
  232. `0+PhjSBIbjRpLmX`iq8&,$10$b0'-A$m9T@-0Sli$`"`EY,3c'(pbdCL2(C3kq+
  233. E0NdY`P&E2c+l$11[4M+0r,Vm[-,mh2bFl-+beNh(M$3@0LfZ865c5icFX0-!01D
  234. AiFjBhh4[ilJa+,iZrY246&Xp%()qSa3jr&'+(+M!ej2NcFrpVi,*q1R-f(R1@Be
  235. iZ+fbDZdUm[+l4QCY`6,RR[eA89*8E#`Tbrr-3JT,Y"d)9"VJSLCR+ZiR*GfB2D*
  236. Trm+#FIpj-"R1#"Jp#SbXrEi!-m`dNC1GAFSZaR&0HaD9M2SXEh"XPIj4Fj!!BGf
  237. ,4Z%H@Pf+*mc91$h,biT+eYV4#mf6SeI[phiMrhrAK+Z)T4#eqq%L@9P%e+jGZff
  238. VTQXZ)5*-D&ZhGQdLJQ#)ABNGU61SNZTH[(RP[m4AmHE'Y[K-*Ij5e[FbpkY[Mke
  239. c+b*Ca*i%L5pXLe!J!jrDjQ-rJAkEI@[cYQCeY58FYSNiir9LKL&Ue4J+XBeV)lE
  240. 6XihPCGLX0ri2!*!$$8jAmLY""M"K4QlP*k&NXqc)M"*1RN@6Nk1%Nq2d#1dLR%`
  241. "eK0i[3"B!(PaJ#qQK"&1d)pBi#CpGRR*r$`jV518F#-mCQ6!bA-bi'6!eMLH(2k
  242. !(AAiairJ#)dUp3$K'CU"jSAP5KSB+Ye*ck2(AF*j@K3#B@q-dX)2"M@m3*ecUB3
  243. D65S5TN,XET8b`b%B0NDD4Mh'V,[&Kfj'aqm93rF34BdjjRfLaSI`))%m!'k!8,R
  244. %$)MB9[Jf*aE)*XcZ&XU-$lY1YdC@8%1`ahJM*A(`8LEGAa`6rc6NY#Ld'[1-a1K
  245. 2)T0GP4HP4Ed0qh,`[k#rR43)2BDPlF(VEUGcM#F%D(&R*RR1ALS0Bp6'kF-PI,2
  246. lc10I)C*3&iKF@K`K'4IP5("c$&r$&p[`NK9-NM(Ska2`C)L&B(*8XK(#3'8Np4a
  247. IUja*Keja*mKJS`6B)K,8`iHlUT4@$6plAR+,j[-G'QGDX`Q%!Hq#6UF`9R-jUN9
  248. ec"`!5*EAa0C!@HhS#Sd*2T,`5ZQX"I4M1IQm)5D)JfB#K*)MdLrK9I6fb8ie@P6
  249. i6!D"Ba4r)%@c,U"DfrJi#VC*aJNMd6J,3a!p8S!LE'kF+k#9F9E1Z6$1KA-UHJ2
  250. "M#m!Iq,0M(D+eZP)GB5&Q*!!5hUb&++h%cU#'h(TqNlb!24*mVj5!TRXH$C(q(2
  251. *0@EE#C*kLZX6J5T9!kL"+86Ge)'RcN3J5T!!3'L""AeD%J9$-JVFYjJ(PJZDH@N
  252. Xp"%BiGGN+HlY`G$"QSDUQiSHUc[%M+p8GNq@16R2,SAe*BBl6pG-X8+Vr0b"HZM
  253. F2+'@e3&!j+L3!$cj#[UF!SjTE*acKHUm%fI!S(8Xm[Hi9Nd,j9UL$59MCp&kb$6
  254. ,c5aE-iUPJBA#MFD)[3lB&QfDXrr'E1$NYCQ'ECe),HPT,$A)dmcel[F&[JTGRlX
  255. IBMG`hFJ4ZjP#)qhZ-99pI'i*aI1XDFE@jZHTZl6#aLN2fbMV8dAh$"JhH"IeAfi
  256. HL[V9$Z'!E+*$XXG&3Y`N0)0TRA!Dk@3HRh4)95'Y&+Sm@%EjCC+IPrk@h%miF8`
  257. qBXE#Ab'Za9YeN6X&Dm2&"T*#XD01fc`PDDJ(9$(5m*,*SPfm,aH,G[&EZEKZ&cI
  258. PBY%ZVXV&4IDqkr4AU$G"[mCp'r5ALEQjC1kAm"jI9leJefhQiNif9B)iFleGp2Z
  259. maACa-m#q-$#ElrrH+["TKlGba+&@"@V,+e0%9p4ckji83#BE#QT5iKEFmAqmY(e
  260. G9k5%pFC4re5NH5bhTaeh25K*NkV3lcf)EC4S3L`lN!"L8QNk)1++"XJ0,!2Z4'S
  261. BZU%I0GQj-Sh$me"df2(+6AV-[aVAQpA+KU$'&5[9qEf'S'ZPqQ)MR@c%UDSpA1B
  262. f"U"PE+qiISH6Ej@ZPcU4E"U$eiQ9Ld4hj83V&RI#P41ckE+bP5+01CbRID-%R6!
  263. G+X2pT46YKER-6RV9lX1KI%peadfkfN-Eid!j86dY,-NlYqf8cUHBjNE*Jf,H8DH
  264. 6kkCDiG!@aL8e"DR[CKX'5ZXC5G*mA9pV42S8L2kYb,9c8V9a*hZcbk&Q-+E$0"k
  265. QilI+0h$"jHYQRF#82Sh'H["D%TVqYF2@1*X*fRI$VKAk4SL&Z6p)dFDMIk1Afl[
  266. &kFRLhSP&kFm"2ai[6QJ+'((L!qrY)&4cZfMa2R&aZcJlAEbA+0`ZmZCimAlAF,X
  267. Brr%iqceMr'GMULJ`C-*JqN[MI`!!*km!!!%!N!-"&!#3!a3!N!-b26!a-M-d06B
  268. h!$Jj!*!$%*!4#'&PG'8ZFfPd!!)!N!06594%8dP8)3#3$&0*9%46593K!*!BTi-
  269. 4SJ#3!aB!!!&'#L#X3B"2K9@'BBTPN@Q9EjTeRhRB!+`$,3!()(j"c%k%6meKLfk
  270. @EjX!IJF6!!!J)!F@!!!J(J!!!Vj19J!!51Irr%+R2c`!!$mm!#![2)3%!!bSY5!
  271. I0!!f2!!"3QF[2%Y$5&+TR$JI$%3!!'F!!1i-4!!"C`!!mN*'3UF[2%Y$5!#3!a!
  272. !+`!&!4J"qJ#3"J-!N!-"!*!$!43!N!-8!*!$-J!S)JJ2EJ#3!a`!-J!!8f9dC`#
  273. 3!`S!!2rr!*!&+'Md+AB:
  274.  
  275. ==============================================================================
  276. Ross Brown, Dept. 7C22  < Bell-Northern Research     >  Just the facts, ma'am.
  277. Advisor, Telemgmt Svcs  < P. O. Box 3511, Station C  >  We don't care whose
  278. ross@bnr.ca             < Ottawa, ON, Canada K1Y 4H7 >  opinions yours aren't.
  279. ==============================================================================
  280.  
  281.  
  282. +++++++++++++++++++++++++++
  283.  
  284. From: andrewb@nezsdc.icl.co.nz (Andrew Bevin)
  285. Date: Thu, 21 Jan 93 20:48:32 GMT
  286. Organization: Fujitsu New Zealand
  287.  
  288. In article <1993Jan20.184006.15422@uts.uni-c.dk> povlphp@uts.uni-c.dk (Povl H. Pedersen) writes:
  289. >Subject says it all. Please mail me an aete TNPL if you have one.
  290. >I am going to start doing some AE stuff.
  291. >-- 
  292. >Povl H. Pedersen   -   Macintosh specialist. Knows some DOS and UNIX too.
  293. >pope@imv.aau.dk    -   povlphp@uts.uni-c.dk
  294.  
  295. I would also, greatly appreciate an aete TNPL, if you have such a beast
  296. please mail a copy to me as well.
  297.  
  298.  
  299. - -- 
  300. Andrew Bevin                                       andrewb@icl.co.nz
  301. SDC, Fujitsu New Zealand                      ## I do not speak for Fujitsu! ##
  302. Auckland, New Zealand   
  303. - -------------------------------------------------------------------------------
  304.  
  305. +++++++++++++++++++++++++++
  306.  
  307. From: jpm@cs.hut.fi (Jussi-Pekka Mantere)
  308. Date: 22 Jan 93 00:29:27 GMT
  309. Organization: Helsinki University of Technology, Finland
  310.  
  311. Povl H. Pedersen <povlphp@uts.uni-c.dk> writes:
  312.  
  313.    Subject says it all. Please mail me an aete TNPL if you have one.
  314.    I am going to start doing some AE stuff.
  315.  
  316. You'd rather want to use an aete HyperCard stack, found on the
  317. Developer CD's.
  318.  
  319. (Sorry, I don't have the CD handy, but will look the path up if
  320. necessary.)
  321.  
  322. Cheers,
  323.  
  324. Jussi-Pekka Mantere
  325.  
  326. +++++++++++++++++++++++++++
  327.  
  328. From: lai@Apple.COM (Ed Lai)
  329. Date: 23 Jan 93 15:48:43 GMT
  330. Organization: Apple Computer Inc, Cupertino, CA
  331.  
  332. In article <JPM.93Jan22022927@cardhu.cs.hut.fi> jpm@cs.hut.fi (Jussi-Pekka Mantere) writes:
  333. >Povl H. Pedersen <povlphp@uts.uni-c.dk> writes:
  334. >
  335. >   Subject says it all. Please mail me an aete TNPL if you have one.
  336. >   I am going to start doing some AE stuff.
  337. >
  338. >You'd rather want to use an aete HyperCard stack, found on the
  339. >Developer CD's.
  340. >
  341.  
  342. You can also find the latest version (among other Apple Events related stuff)
  343. from ftp.apple.com in the directory /pub/appleevents
  344.  
  345. >(Sorry, I don't have the CD handy, but will look the path up if
  346. >necessary.)
  347. >
  348. >Cheers,
  349. >
  350. >Jussi-Pekka Mantere
  351.  
  352. /* Disclaimer: All statments and opinions expressed are my own */
  353. /* Edmund K. Lai                                               */
  354. /* Apple Computer, MS37-UP                                     */
  355. /* 20525 Mariani Ave,                                          */
  356. /* Cupertino, CA 95014                                         */
  357. /* (408)974-6272                                               */
  358. zW@h9cOi
  359.  
  360. ---------------------------
  361.  
  362. From: gwatts@fnalo.fnal.gov
  363. Subject: Verifying valid handles, how to?
  364. Organization: Fermi National Accelerator Lab
  365. Date: Fri, 22 Jan 1993 07:55:20 GMT
  366.  
  367. Hi all,
  368.   The first part is an amusing story.  The second request for help is aimed
  369. at anyone who is good at the memory manager. :)  Everyone, right? :)
  370.   I spent about 4 hours tracking down a but in my Think C 5.0.3 program
  371. yesterday.  It was crazy.  My color table kept getting corrupted.  I would
  372. never bomb in the same place.  Sometimes the "rb" command in MacsBug wouldn't
  373. even work!  I had icons explode into little dots.
  374.   Turns out (sheepish grin) I was deleteing an object twice. :)
  375.   At any rate, I was thinking.  I've got only indirect objects in my project.
  376. This means every object is a handle, right?  Well, why not, in the debug
  377. version of the message dispatcher (oopDebug library) put a little code that
  378. will check the object is infact allocated as a handle?
  379.   I checked out the routine in msg.c (in the oops Libraries folder), and
  380. the handle is stored in register a1.  I don't know, however, how to check
  381. if it is a valid handle without causing an error (bus or otherwise) of
  382. somesort.  Especially if it is a random number!  Anyone know?  Is there
  383. some memory manager routine, given a suspected handle, will tell me this?
  384.   By the way -- I do zero all objects after I delete them.  This case was
  385. a little more subtle than that (so don't yell at me :)).
  386.  
  387.     Cheers,
  388.         Gordon.
  389.  
  390.  
  391. +++++++++++++++++++++++++++
  392.  
  393. From: neeri@iis.ethz.ch (Matthias Neeracher)
  394. Date: 22 Jan 93 18:09:34 GMT
  395. Organization: Integrated Systems Laboratory, ETH, Zurich
  396.  
  397. In article <1993Jan22.015520.1@fnalo.fnal.gov>, gwatts@fnalo.fnal.gov writes:
  398. >   At any rate, I was thinking.  I've got only indirect objects in my project.
  399. > This means every object is a handle, right?  Well, why not, in the debug
  400. > version of the message dispatcher (oopDebug library) put a little code that
  401. > will check the object is infact allocated as a handle?
  402. >   I checked out the routine in msg.c (in the oops Libraries folder), and
  403. > the handle is stored in register a1.  I don't know, however, how to check
  404. > if it is a valid handle without causing an error (bus or otherwise) of
  405. > somesort.  Especially if it is a random number!  Anyone know?  Is there
  406. > some memory manager routine, given a suspected handle, will tell me this?
  407.  
  408. Here you go. This code is not guaranteed to work 100% of the time, but I doubt
  409. you will get it to produce an address error for any normal memory setup (One
  410. exception I can think of are macs with a memory upgrade that makes the ROM
  411. appear in the middle of the application heap).
  412.  
  413. /* Heuristic to determine whether a given address is a Handle            */
  414. /* Based on the articles of Lloyd Lim and Matthew T Russotto in the UMPG */
  415. /* This code may be redistributed without any restrictions               */
  416.  
  417. Boolean RealHandle(void * addr)
  418. {
  419.    THz   sysZone;
  420.    THz   applZone;
  421.    THz   heapZone;
  422.    
  423.    addr  =  StripAddress(addr);
  424.    if (addr && !((long) addr & 1))  {
  425.       sysZone  =  SystemZone();
  426.       applZone =  ApplicZone();
  427.       if (addr >= (Ptr) &sysZone->heapData   && 
  428.           addr <  (Ptr) sysZone->bkLim          ||
  429.           addr >= (Ptr) &applZone->heapData  && 
  430.           addr <  (Ptr) applZone->bkLim
  431.          )
  432.          if (*(long *)addr && !(*(long *)addr & 1)) {
  433.             heapZone =  HandleZone(addr);
  434.             if (!MemError())
  435.                if (heapZone == sysZone || heapZone == applZone)
  436.                   return true;
  437.          }
  438.    }
  439.    
  440.    return false;
  441. }
  442.  
  443. Matthias
  444.  
  445. - -----
  446. Matthias Neeracher                                      neeri@iis.ethz.ch
  447.  `We say "gestalt" when things combine to act in ways we can't explain'
  448.                              -- Marvin Minsky, _The Society Of Mind_
  449.  
  450. +++++++++++++++++++++++++++
  451.  
  452. From: keith@taligent.com (Keith Rollin)
  453. Date: 23 Jan 93 00:04:58 GMT
  454. Organization: Taligent
  455.  
  456. In article <NEERI.93Jan22190934@iis.ethz.ch>, neeri@iis.ethz.ch (Matthias
  457. Neeracher) wrote:
  458. > In article <1993Jan22.015520.1@fnalo.fnal.gov>, gwatts@fnalo.fnal.gov writes:
  459. > >   At any rate, I was thinking.  I've got only indirect objects in my project.
  460. > > This means every object is a handle, right?  Well, why not, in the debug
  461. > > version of the message dispatcher (oopDebug library) put a little code that
  462. > > will check the object is infact allocated as a handle?
  463. > >   I checked out the routine in msg.c (in the oops Libraries folder), and
  464. > > the handle is stored in register a1.  I don't know, however, how to check
  465. > > if it is a valid handle without causing an error (bus or otherwise) of
  466. > > somesort.  Especially if it is a random number!  Anyone know?  Is there
  467. > > some memory manager routine, given a suspected handle, will tell me this?
  468. > Here you go. This code is not guaranteed to work 100% of the time, but I doubt
  469. > you will get it to produce an address error for any normal memory setup (One
  470. > exception I can think of are macs with a memory upgrade that makes the ROM
  471. > appear in the middle of the application heap).
  472. > /* Heuristic to determine whether a given address is a Handle            */
  473. > /* Based on the articles of Lloyd Lim and Matthew T Russotto in the UMPG */
  474. > /* This code may be redistributed without any restrictions               */
  475. > Boolean RealHandle(void * addr)
  476. > {
  477. >    THz   sysZone;
  478. >    THz   applZone;
  479. >    THz   heapZone;
  480. >    
  481. >    addr  =  StripAddress(addr);
  482. >    if (addr && !((long) addr & 1))  {
  483. >       sysZone  =  SystemZone();
  484. >       applZone =  ApplicZone();
  485. >       if (addr >= (Ptr) &sysZone->heapData   && 
  486. >           addr <  (Ptr) sysZone->bkLim          ||
  487. >           addr >= (Ptr) &applZone->heapData  && 
  488. >           addr <  (Ptr) applZone->bkLim
  489. >          )
  490. >          if (*(long *)addr && !(*(long *)addr & 1)) {
  491. >             heapZone =  HandleZone(addr);
  492. >             if (!MemError())
  493. >                if (heapZone == sysZone || heapZone == applZone)
  494. >                   return true;
  495. >          }
  496. >    }
  497. >    
  498. >    return false;
  499. > }
  500.  
  501. I think that the above routine tries to validate any value that you might
  502. have lying around. However, if you have a value that you know at one time
  503. was a handle, you might want to check to see if it's on the free chain or
  504. not (this code is from MacApp):
  505.  
  506. Boolean IsFreeHandle(Handle aHandle)
  507. {
  508.     THz applZone = ApplicZone();
  509.     Handle currHandle = (Handle) applZone->hFstFree;
  510.  
  511.     while (currHandle != NULL)
  512.     {
  513.         if (currHandle == aHandle)
  514.             return TRUE;
  515.         currHandle = (Handle) * currHandle;
  516.     }
  517.     return FALSE;
  518. }
  519.  
  520. If course, nothing will help you if the master pointer has been
  521. re-allocated. Your old handle will now be pointing to a new, perfectly
  522. valid block of memory. I think the only thing you can do at that point is
  523. check the handle size against sizeof(TYourClass).
  524.  
  525. Greg Marriott (who was seen the other night at the Red Pepper with Cindy
  526. Jasper) wrote an INIT that tries to detect double-dispose bugs. It's on
  527. Apple's Developer CD and probably other places. Here are the release notes
  528. for your reading pleasure:
  529.  
  530. ;
  531. ;    DoubleTrouble - by Greg Marriott
  532. ;
  533. ;    ) 1992, Apple Computer, Inc.
  534. ;
  535. ;    DoubleTrouble is a debugging utility made to catch a common programming
  536. error:
  537. ;    freeing a handle that has already been freed.  (I call these errors
  538. Rdouble
  539. ;    dispose bugsSI)
  540. ;
  541. ;    When _DisposeHandle is called on a handle, the memory manager adds the
  542. handle
  543. ;    to its Rfree list,S a linked list of handles available for the allocator
  544. to use.
  545. ;    Calling _DisposeHandle on that handle again is usually benign.  The
  546. memory
  547. ;    manager dereferences the handle, pointing to the next handle in the free
  548. list.
  549. ;    If the the dereferenced handle points to the first handle in a master
  550. pointer block,
  551. ;    however, the handle appears valid because it points to a real block.  The
  552. memory
  553. ;    manager fails to realize the block is NOT a relocatable block (all master
  554. pointer
  555. ;    blocks are nonrelocatable), and marks it free (yikes!).  The freed master
  556. pointer
  557. ;    block is then used in a future allocation (usually very soon after being
  558. freed).
  559. ;    This mangles several master pointers and the free list.  Crashes soon
  560. follow.
  561. ;
  562. ;    This kind of bug is very hard to track down, and usually difficult to
  563. reproduce,
  564. ;    because master pointer blocks contain 64 handles (by default, some
  565. programs
  566. ;    change this behavior).  So, this situation only comes up about 1/64th of
  567. the
  568. ;    time.  When it happens, though, the results are inevitably catastrophic.
  569. ;
  570. ;    DoubleTrouble compares each handle being disposed to every handle in the
  571. free list of
  572. ;    the zone containing the handle.  If the handle is already in the free
  573. list, DoubleTrouble
  574. ;    breaks into the debugger with a message indicating whatUs going on. 
  575. Continuing execution
  576. ;    will stuff memWZErr (WhichZone failed, -111) into MemErr and d0 and
  577. return to the caller
  578. ;    (and NOT call through to _DisposeHandle).
  579. ;    
  580.  
  581. - -----
  582. Keith Rollin
  583. Phantom Programmer
  584. Taligent, Inc.
  585.  
  586. +++++++++++++++++++++++++++
  587.  
  588. From: peter@cujo.curtin.edu.au (Peter N Lewis)
  589. Organization: NCRPDA, Curtin University
  590. Date: Sat, 23 Jan 1993 10:01:36 GMT
  591.  
  592. In article <1993Jan22.015520.1@fnalo.fnal.gov>, gwatts@fnalo.fnal.gov
  593. wrote:
  594.  
  595. > the handle is stored in register a1.  I don't know, however, how to check
  596. > if it is a valid handle without causing an error (bus or otherwise) of
  597. > somesort.  Especially if it is a random number!  Anyone know?  Is there
  598.  
  599. here's a random attempt at it.  First check that the handle is even.  Then
  600. check that it points to an area inside your heap or inside the system heap,
  601. then check that h^ is inside the heap as well, and finally that recover
  602. handle gives the right value.
  603.  
  604.  function InsideHeap (p: univ ptr; hz: THz): boolean;
  605.  begin
  606.   InsideHeap := (longInt(p) >= longInt(hz)) & (longInt(p) <
  607. longInt(hz^.bkLim));
  608.  end;
  609.  
  610.  function ValidHandle (h: univ handle): boolean;
  611.   var
  612.    valid: boolean;
  613.  begin
  614.   valid := false;
  615.   if BAND(h, 1) = 0 then begin
  616.    if InsideHeap(h, ApplicZone) then begin
  617.     valid := (BAND(h^, 1) = 0) & InsideHeap(h^, ApplicZone);
  618.    end
  619.    else if InsideHeap(h, SystemZone) then begin
  620.     valid := (BAND(h^, 1) = 0) & InsideHeap(h^, SystemZone);
  621.    end;
  622.   end;
  623.   if valid then begin
  624.    valid := RecoverHandle(h^) = h;
  625.   end;
  626.   ValidHandle := valid;
  627.  end;
  628.  
  629. (Code tried and tested, but by no means guarenteed)
  630.  
  631. That would seem to be a good start...
  632.    Peter.
  633.  
  634. _______________________________________________________________________
  635. Peter N Lewis <peter@cujo.curtin.edu.au>             Ph: +61 9 368 2055
  636.  
  637. ---------------------------
  638.  
  639. From: bpb9204@tamsun.tamu.edu (Brent Burton)
  640. Subject: Memory allocation in your app
  641. Date: 22 Jan 1993 21:49:49 -0600
  642. Organization: Texas A&M Univ., Inc.
  643.  
  644. Just a quick question.
  645.  
  646. When your application  starts up, it gets a contiguous block of memory
  647. in which the program has its heap and stack.
  648.  
  649. I was looking through the Mem Mgr and found out that you can create more
  650. than one memory zone, where the NewPtr, NewHandle, and Dispose* calls
  651. are active.  Does this mean that, for example in a compiler, you may
  652. allocate hundreds of little chunks of memory, and then when you are
  653. done using them, you may deallocate them all by destroying that memory
  654. zone?  
  655.  
  656. Also, when your application exits, any chunks that were allocated from
  657. the New* calls are automatically returned, I assume? 
  658.  
  659. The reasons I ask these are for those one-shot programming tasks
  660. where I need to create some complex data structure, and then would
  661. like to free it all at once.
  662.  
  663. thanks,
  664. - -Brent
  665. - -- 
  666. +-------------------------+
  667. | Brent Burton    N5VMG   |    
  668. | bpb9204@tamsun.tamu.edu |  
  669. +-------------------------+ 
  670.  
  671. +++++++++++++++++++++++++++
  672.  
  673. From: orpheus@reed.edu (P. Hawthorne)
  674. Organization: Reed College, Portland, OR
  675. Date: Sat, 23 Jan 1993 05:41:28 GMT
  676.  
  677.   bpb9204@tamsun.tamu.edu (Brent Burton) asks:
  678. : I was looking through the Mem Mgr and found out that you can create more
  679. : than one memory zone, where the NewPtr, NewHandle, and Dispose* calls
  680. : are active.  Does this mean that, for example in a compiler, you may
  681. : allocate hundreds of little chunks of memory, and then when you are
  682. : done using them, you may deallocate them all by destroying that memory
  683. : zone?  
  684.  
  685.   You can do this, yes. It's remarkably simple. I think Rich Siegel posted
  686. a snippet of code that does this a couple of months ago. But, remember,
  687. the Macintosh memory manager is not designed to handle the oodles and
  688. oodles of blocks that your average compiler wants to deal with. If you have
  689. the time and the inclination, you can write a dynamic memory allocator
  690. with the same functionality as the memory manager, with remarkably
  691. different resource requirements.
  692.  
  693.   Here's an Object Pascal class I was working on last month.  It aint
  694. production quality, nor would it build right off the bat, but it's
  695. informative. It was going to become the memory zone class for the framework
  696. I've been working on, but the recent example apps I've been working on
  697. don't need variable length blocks, so it has been left to gather dust.
  698.  
  699.   It's your basic double two-way circular linked list of free and allocated
  700. blocks, but it doesn't use tags per se. It isn't very faithful to the sort
  701. of allocs you generally see around, but then, it's really cool for the
  702. stone age Macintosh memory model, so, I guess it's okay. Sometimes
  703. reinventing the wheel can be a lot of fun! I'd like to implement the binary
  704. free tree technique that's mentioned in an exercise in Knuth, but haven't
  705. had time. Maybe someone else could do it. I've radically changed the
  706. WackyHandle datatype so that it can migrate between temporary memory and
  707. application memory at will, for instance on suspend and resume events, but
  708. this class doesn't grok the new interface.
  709.  
  710.   Oh, by the way, it uses offsets from a handle instead of pointers so
  711. there is some dereferencing overhead, which reflects my idiosyncratic two
  712. cents worth on memory management. Also, it presently uses a method for
  713. dereferencing blocks, which reflects my feelings about typing while coding
  714. extremely dangerous and sleazy hacks like this.
  715.  
  716.   Commentary more than just welcome.
  717.  
  718.   Cut here.
  719.  
  720.  
  721. Unit QPool;
  722.  
  723. Interface
  724.  
  725. Uses
  726.  Core;
  727.  
  728. Type
  729.  BlockO = Longint;
  730.  BlockP = ^BlockR;
  731.  BlockR = Record
  732.    length: Longint;
  733.    backBlock, nextBlock: BlockO;
  734.    free: Boolean;
  735.    backFree, nextFree: BlockO;
  736.   End;
  737.  BlockA = Array[1..256] Of BlockR;
  738.  BlockAP = ^BlockA;
  739.  BlockAH = ^BlockAP;
  740.  
  741. Const
  742.  BlockRSize = Longint(SizeOf(BlockR));
  743.  SizeOfFreeLinks = Longint(SizeOf(BlockO) + SizeOf(BlockO));
  744.  poolHead = 0;
  745.  freeHead = BlockRSize;
  746.  HeaderSize = Longint(BlockRSize + BlockRSize);
  747.  
  748. Type
  749.  QPool = Object(QContent)
  750.    pool: BlockAH;
  751.  
  752.    presentCapacity: Longint;
  753.    usedCapacity: Longint;
  754.    usualCapacity: Longint;
  755.    growthCapacity: Longint;
  756.  
  757.    freeCount: Longint;
  758.    freeCursor: BlockO;
  759.  
  760.    usesTemporaryMemory: Boolean;
  761.  
  762.    Function QPool.Construct: Boolean;
  763.    override;
  764.    Procedure QPool.Destruct;
  765.    override;
  766.    Procedure QPool.Loosen;
  767.    override;
  768.    Procedure QPool.Fasten;
  769.    override;
  770.  
  771.    Procedure QPool.Check;
  772.  
  773.    Function QPool.Ref (aBlock: BlockO): BlockP;
  774.    Function QPool.AvailBlock (Var aBlock: BlockO; aSize: Longint): Boolean;
  775.    Procedure QPool.ReleaseBlock (Var aBlock: BlockO);
  776.    Procedure QPool.ChangeBlock (source, destination: BlockO);
  777.    Procedure QPool.Compact;
  778.   End;
  779.  
  780.  
  781. Procedure QuiverTest;
  782.  
  783. Implementation
  784.  
  785. Function AvailWackyHandle (Var aHandle: Univ Handle; aSize: Longint; temporary: Boolean): Boolean;
  786.  Var
  787.   aResult: OSErr;
  788.  Begin
  789.  If temporary Then
  790.   Begin
  791.   aHandle := MFTempNewHandle(aSize, aResult);
  792.   If aHandle <> Nil Then
  793.    If Not ourMemory.AddTemporaryHandle(aHandle) Then
  794.     Begin
  795.     MFTempDisposHandle(aHandle, aResult);
  796.     aHandle := Nil;
  797.     End;
  798.   End
  799.  Else
  800.   aHandle := NewHandleClear(aSize);
  801.  AvailWackyHandle := (aHandle <> Nil);
  802.  End;
  803.  
  804. Procedure ReleaseWackyHandle (Var aHandle: Univ Handle; temporary: Boolean);
  805.  Var
  806.   aResult: OSErr;
  807.  Begin
  808.  If temporary Then
  809.   Begin
  810.   MFTempDisposHandle(aHandle, aResult);
  811.   ourMemory.RemoveTemporaryHandle(aHandle);
  812.   End
  813.  Else
  814.   DisposHandle(aHandle);
  815.  aHandle := Nil;
  816.  End;
  817.  
  818. Procedure LockWackyHandle (aHandle: Univ Handle; temporary: Boolean);
  819.  Var
  820.   aResult: OSErr;
  821.  Begin
  822.  If temporary Then
  823.   MFTempHLock(aHandle, aResult)
  824.  Else
  825.   HLock(aHandle);
  826.  End;
  827.  
  828. Procedure UnlockWackyHandle (aHandle: Univ Handle; temporary: Boolean);
  829.  Var
  830.   aResult: OSErr;
  831.  Begin
  832.  If temporary Then
  833.   MFTempHUnlock(aHandle, aResult)
  834.  Else
  835.   HUnlock(aHandle);
  836.  End;
  837.  
  838. Function GrowWackyHandle (Var aHandle: Univ Handle; aSize: Longint; temporary: Boolean): OSErr;
  839.  Var
  840.   aNewHandle: Handle;
  841.   aResult: OSErr;
  842.   aBoolean: Boolean;
  843.  Begin
  844.  If temporary Then
  845.   Begin
  846.   aNewHandle := MFTempNewHandle(aSize, aResult);
  847.   If aNewHandle = Nil Then
  848.    Begin
  849.    GrowWackyHandle := aResult;
  850.    Exit(GrowWackyHandle);
  851.    End;
  852.   MFTempHLock(aNewHandle, aResult);
  853.   MFTempHLock(aHandle, aResult);
  854.   BlockMove(@aHandle^^, @aNewHandle^^, aSize);
  855.   MFTempDisposHandle(aHandle, aResult);
  856.   ourMemory.RemoveTemporaryHandle(aHandle);
  857.   aHandle := aNewHandle;
  858.   aBoolean := ourMemory.AddTemporaryHandle(aHandle);
  859.   GrowWackyHandle := noErr;
  860.   End
  861.  Else
  862.   GrowWackyHandle := GrowHandle(aHandle, aSize);
  863.  End;
  864.  
  865. Procedure SizeWackyHandle (Var aHandle: Univ Handle; aSize: Longint; temporary: Boolean);
  866.  Var
  867.   aNewHandle: Handle;
  868.   aResult: OSErr;
  869.   aBoolean: Boolean;
  870.  Begin
  871.  If temporary Then
  872.   Begin
  873.   aNewHandle := MFTempNewHandle(aSize, aResult);
  874.   If aNewHandle = Nil Then
  875.    Exit(SizeWackyHandle);
  876.   BlockMove(@aHandle^^, @aNewHandle^^, aSize);
  877.   MFTempDisposHandle(aHandle, aResult);
  878.   ourMemory.RemoveTemporaryHandle(aHandle);
  879.   aHandle := aNewHandle;
  880.   aBoolean := ourMemory.AddTemporaryHandle(aHandle);
  881.   MFTempHLock(aHandle, aResult);
  882.   End
  883.  Else
  884.   SizeHandle(aHandle, aSize);
  885.  End;
  886.  
  887. Function QPool.Construct: Boolean;
  888.  Var
  889.   freeP, poolP, newP: BlockP;
  890.  
  891.  Begin
  892.  Construct := false;
  893.  If Not Inherited Construct Then
  894.   Exit(Construct);
  895.  If (usualCapacity > BlockRSize) & AvailWackyHandle(pool, Longint(HeaderSize + usualCapacity), usesTemporaryMemory) Then
  896.   Begin
  897.   LockWackyHandle(pool, usesTemporaryMemory);
  898.   presentCapacity := HeaderSize + usualCapacity;
  899.  
  900.   poolP := Ref(poolHead);
  901.   poolP^.backBlock := HeaderSize;
  902.   poolP^.nextBlock := HeaderSize;
  903.  
  904.   freeP := Ref(freeHead);
  905.   freeP^.backFree := HeaderSize;
  906.   freeP^.nextFree := HeaderSize;
  907.   freeP^.free := true;
  908.  
  909.   newP := Ref(HeaderSize);
  910.   newP^.backBlock := poolHead;
  911.   newP^.nextBlock := poolHead;
  912.   newP^.backFree := freeHead;
  913.   newP^.nextFree := freeHead;
  914.   newP^.length := usualCapacity - BlockRSize;
  915.   newP^.free := true;
  916.  
  917.   poolP^.free := false;
  918.   poolP^.length := 0;
  919.   freeP^.free := true;
  920.   freeP^.length := 0;
  921.   freeP^.nextBlock := 0;
  922.   freeP^.backBlock := 0;
  923.  
  924.   freeCount := 1;
  925.   freeCursor := HeaderSize;
  926.   End
  927.  Else If AvailWackyHandle(pool, HeaderSize, usesTemporaryMemory) Then
  928.   Begin
  929.   LockWackyHandle(pool, usesTemporaryMemory);
  930.   presentCapacity := HeaderSize;
  931.  
  932.   poolP := Ref(poolHead);
  933.   poolP^.backBlock := poolHead;
  934.   poolP^.nextBlock := poolHead;
  935.  
  936.   freeP := Ref(freeHead);
  937.   freeP^.backFree := freeHead;
  938.   freeP^.nextFree := freeHead;
  939.   freeP^.free := true;
  940.   freeCursor := freeHead;
  941.   End
  942.  Else
  943.   Exit(Construct);
  944.  
  945.  usedCapacity := HeaderSize;
  946.  Construct := true;
  947.  End;
  948.  
  949. Procedure QPool.Destruct;
  950.  Begin
  951.  ReleaseWackyHandle(pool, usesTemporaryMemory);
  952.  Inherited Destruct;
  953.  End;
  954.  
  955. Procedure QPool.Loosen;
  956.  Begin
  957.  UnlockWackyHandle(pool, usesTemporaryMemory);
  958.  Inherited Loosen;
  959.  End;
  960.  
  961. Procedure QPool.Fasten;
  962.  Begin
  963.  Inherited Fasten;
  964.  LockWackyHandle(pool, usesTemporaryMemory);
  965.  End;
  966.  
  967. Function QPool.Ref (aBlock: BlockO): BlockP;
  968.  Begin
  969.  If aBlock < 0 Then
  970.   Debugger
  971.  Else If aBlock > presentCapacity Then
  972.   Debugger;
  973.  Ref := BlockP(Clean(LongintPtr(pool)^) + aBlock);
  974.  End;
  975.  
  976. Function QPool.AvailBlock (Var aBlock: BlockO; aSize: Longint): Boolean;
  977.  Var
  978.   startCursor: BlockO;
  979.   freeCursorP: BlockP;
  980.   leastSize, requiredSize, thisSize, newCapacity: Longint;
  981.   aBlockP, poolP, lastP, freeP: BlockP;
  982.   spareO: BlockO;
  983.   spareP: BlockP;
  984.   spareLength: Longint;
  985.   gotExtra: Boolean;
  986.  Begin
  987.  aSize := aSize - SizeOfFreeLinks;
  988.  If aSize < 0 Then
  989.   aSize := 0;
  990.  AvailBlock := false;
  991.  
  992.  If freeCount > 0 Then
  993.   Begin
  994.   leastSize := aSize + BlockRSize;
  995.   requiredSize := leastSize + BlockRSize;
  996.  
  997.   startCursor := freeCursor;
  998.   Repeat
  999.    freeCursorP := Ref(freeCursor);
  1000.    If (freeCursor <> freeHead) And (Not freeCursorP^.free) Then
  1001.     Debugger;
  1002.    thisSize := freeCursorP^.length;
  1003.    If (freeCursor <> freeHead) & ((thisSize = leastSize) | (thisSize >= requiredSize)) Then
  1004.     Begin
  1005.     aBlock := freeCursor;
  1006.     usedCapacity := usedCapacity + BlockRSize + aSize;
  1007.  
  1008.     freeCursorP^.length := aSize;
  1009.     freeCursorP^.free := false;
  1010.     freeCount := freeCount - 1;
  1011.  
  1012.     spareLength := thisSize - aSize;
  1013. {If spareLength = 0 Then}
  1014. {DebugStr('Exact fit!');}
  1015. {Writeln('Exact fit at ', LongintToString(freeCursor), '.');}
  1016. {else}
  1017. {Writeln('Fit at ', LongintToString(freeCursor), '.');}
  1018.  
  1019.     If spareLength = 0 Then
  1020.      Begin {Cut this block out of the free list}
  1021.      Ref(freeCursorP^.backFree)^.nextFree := freeCursorP^.nextFree;
  1022.      Ref(freeCursorP^.nextFree)^.backFree := freeCursorP^.backFree;
  1023.      freeCursor := freeCursorP^.nextFree;
  1024.      End
  1025.     Else
  1026.      Begin
  1027.      spareO := freeCursor + BlockRSize + aSize;
  1028.      spareP := Ref(spareO);
  1029.  
  1030. {Replace this block in the free list with a new block toward the end}
  1031.      spareP^.backFree := freeCursorP^.backFree;
  1032.      spareP^.nextFree := freeCursorP^.nextFree;
  1033.      Ref(spareP^.backFree)^.nextFree := spareO;
  1034.      Ref(spareP^.nextFree)^.backFree := spareO;
  1035.  
  1036. {Insert this new block into the pool list}
  1037.      spareP^.nextBlock := freeCursorP^.nextBlock;
  1038.      Ref(spareP^.nextBlock)^.backBlock := spareO;
  1039.      freeCursorP^.nextBlock := spareO;
  1040.      spareP^.backBlock := freeCursor;
  1041.  
  1042.      spareP^.length := spareLength - BlockRsize;
  1043.      spareP^.free := true;
  1044.  
  1045.      freeCursor := spareO;
  1046.      freeCount := freeCount + 1;
  1047.      End;
  1048.  
  1049.     AvailBlock := true;
  1050.     Exit(AvailBlock);
  1051.     End
  1052.    Else
  1053.     freeCursor := freeCursorP^.nextFree;
  1054.   Until freeCursor = startCursor;
  1055.   End;
  1056.  
  1057.  gotExtra := (growthCapacity > BlockRSize);
  1058.  newCapacity := presentCapacity + BlockRSize + aSize + growthCapacity;
  1059.  If GrowWackyHandle(pool, newCapacity, usesTemporaryMemory) <> noErr Then
  1060.   Begin
  1061.   gotExtra := false;
  1062.   newCapacity := newCapacity - growthCapacity;
  1063.   If GrowWackyHandle(pool, newCapacity, usesTemporaryMemory) <> noErr Then
  1064.    Exit(AvailBlock);
  1065.   End;
  1066.  
  1067. {Writeln('Growing for ', LongintToString(presentCapacity), '.');}
  1068.  
  1069.  aBlock := presentCapacity;
  1070.  presentCapacity := newCapacity;
  1071.  usedCapacity := usedCapacity + BlockRSize + aSize;
  1072.  
  1073.  aBlockP := Ref(aBlock);
  1074.  poolP := Ref(poolHead);
  1075.  lastP := Ref(poolP^.backBlock);
  1076.  
  1077.  lastP^.nextBlock := aBlock;
  1078.  aBlockP^.backBlock := poolP^.backBlock;
  1079.  aBlockP^.nextBlock := poolHead;
  1080.  poolP^.backBlock := aBlock;
  1081.  
  1082.  aBlockP^.length := aSize;
  1083.  aBlockP^.free := false;
  1084.  
  1085.  If gotExtra Then
  1086.   Begin
  1087.   spareO := aBlock + BlockRSize + aBlockP^.length;
  1088.   spareP := Ref(spareO);
  1089.   spareP^.free := true;
  1090.   spareP^.length := presentCapacity - spareO - BlockRSize;
  1091.  
  1092.   aBlockP^.nextBlock := spareO;
  1093.   spareP^.backBlock := poolP^.backBlock;
  1094.   spareP^.nextBlock := poolHead;
  1095.   poolP^.backBlock := spareO;
  1096.  
  1097.   freeP := Ref(freeHead);
  1098.   spareP^.backFree := freeP^.backFree;
  1099.   spareP^.nextFree := freeHead;
  1100.   Ref(spareP^.backFree)^.nextFree := spareO;
  1101.   freeP^.backFree := spareO;
  1102.  
  1103.   freeCount := freeCount + 1;
  1104.   End;
  1105.  AvailBlock := true;
  1106.  End;
  1107.  
  1108. Procedure QPool.ReleaseBlock (Var aBlock: BlockO);
  1109.  Var
  1110.   aBlockP: BlockP;
  1111.   cursorO: BlockO;
  1112.   cursorP: BlockP;
  1113.  Begin
  1114.  aBlockP := Ref(aBlock);
  1115.  If aBlockP^.free Then
  1116.   Debugger;
  1117.  aBlockP^.free := true;
  1118.  
  1119.  usedCapacity := usedCapacity - BlockRSize - aBlockP^.length;
  1120.  
  1121.  If freeCount = 0 Then
  1122.   Begin
  1123.   cursorP := Ref(freeHead);
  1124.   cursorP^.backFree := aBlock;
  1125.   cursorP^.nextFree := aBlock;
  1126.   aBlockP^.nextFree := freeHead;
  1127.   aBlockP^.backFree := freeHead;
  1128.   End
  1129.  Else
  1130.   Begin
  1131.   cursorO := freeHead;
  1132.   cursorP := Ref(freeHead);
  1133.  
  1134.   If Abs(cursorP^.backFree - aBlock) <= Abs(cursorP^.nextFree - aBlock) Then
  1135.    Begin {Scan backward from head of free list}
  1136.    If (freeCursor > aBlock) Then
  1137.     cursorP := Ref(freeCursor);
  1138.    Repeat
  1139.     cursorO := cursorP^.backFree;
  1140.     cursorP := Ref(cursorO);
  1141.    Until (cursorO < aBlock) | (cursorO = freeHead);
  1142.    End
  1143.   Else
  1144.    Begin {Scan foreward from head of free list}
  1145.    If (freeCursor < aBlock) Then
  1146.     cursorP := Ref(freeCursor);
  1147.    Repeat
  1148.     cursorO := cursorP^.nextFree;
  1149.     cursorP := Ref(cursorO);
  1150.    Until (cursorO > aBlock) | (cursorO = freeHead);
  1151.    cursorO := cursorP^.backFree;
  1152.    cursorP := Ref(cursorO);
  1153.    End;
  1154.  
  1155.   aBlockP^.nextFree := cursorP^.nextFree;
  1156.   Ref(aBlockP^.nextFree)^.backFree := aBlock;
  1157.   aBlockP^.backFree := cursorO;
  1158.   cursorP^.nextFree := aBlock;
  1159.  
  1160.   If cursorP^.nextBlock = aBlock Then
  1161.    Begin
  1162. {Writeln('Joining ', LongintToString(cursorO), ' to ', LongintToString(aBlock), '.');}
  1163.    cursorP^.length := cursorP^.length + BlockRSize + aBlockP^.length;
  1164.    cursorP^.nextFree := aBlockP^.nextFree;
  1165.    Ref(cursorP^.nextFree)^.backFree := cursorO;
  1166.    cursorP^.nextBlock := aBlockP^.nextBlock;
  1167.    Ref(cursorP^.nextBlock)^.backBlock := cursorO;
  1168.  
  1169.    aBlock := cursorO;
  1170.    aBlockP := cursorP;
  1171.    freeCount := freeCount - 1;
  1172.    End;
  1173.  
  1174.   If aBlockP^.nextBlock = aBlockP^.nextFree Then
  1175.    Begin
  1176. {Writeln('Merging ', LongintToString(aBlock), ' with ', LongintToString(aBlockP^.nextFree), '.');}
  1177.    cursorP := Ref(aBlockP^.nextFree);
  1178.    aBlockP^.length := aBlockP^.length + BlockRSize + cursorP^.length;
  1179.    aBlockP^.nextFree := cursorP^.nextFree;
  1180.    Ref(aBlockP^.nextFree)^.backFree := aBlock;
  1181.    aBlockP^.nextBlock := cursorP^.nextBlock;
  1182.    Ref(aBlockP^.nextBlock)^.backBlock := aBlock;
  1183.    freeCount := freeCount - 1;
  1184.    End;
  1185.   End;
  1186.  
  1187.  freeCount := freeCount + 1;
  1188.  
  1189.  If (aBlock > usualCapacity) & (aBlockP^.nextBlock = poolHead) Then
  1190.   Begin
  1191. {Writeln('Truncating at ', LongintToString(aBlock), '.');}
  1192.  
  1193.   freeCount := freeCount - 1;
  1194.  
  1195.   Ref(freeHead)^.backFree := aBlockP^.backFree;
  1196.   Ref(aBlockP^.backFree)^.nextFree := freeHead;
  1197.  
  1198.   Ref(poolHead)^.backBlock := aBlockP^.backBlock;
  1199.   Ref(aBlockP^.backBlock)^.nextBlock := poolHead;
  1200.  
  1201.   freeCursor := Ref(freeHead)^.nextFree;
  1202.  
  1203.   presentCapacity := aBlock;
  1204.   SizeWackyHandle(pool, presentCapacity, usesTemporaryMemory);
  1205.  
  1206.   End
  1207.  Else
  1208.   freeCursor := aBlock;
  1209.  
  1210.  aBlock := 0;
  1211.  End;
  1212.  
  1213. Procedure QPool.Check;
  1214.  Var
  1215.   previousO, cursorO: BlockO;
  1216.   previousP, cursorP: BlockP;
  1217.   totalFree: Longint;
  1218.  Begin
  1219.  
  1220.  If usedCapacity < 0 Then
  1221.   Debugger;
  1222.  
  1223.  If freeCount < 0 Then
  1224.   Debugger;
  1225.  
  1226. {Check pool list}
  1227.  cursorO := poolHead;
  1228.  cursorP := Ref(poolHead);
  1229.  
  1230.  Repeat
  1231.   previousO := cursorO;
  1232.   previousP := cursorP;
  1233.   cursorO := cursorP^.nextBlock;
  1234.   cursorP := Ref(cursorO);
  1235.   If cursorP^.backBlock <> previousO Then
  1236.    Debugger;
  1237.  Until cursorO = poolHead;
  1238.  
  1239. {Check free list}
  1240.  If freeCount = 0 Then
  1241.   Begin
  1242.   If usedCapacity <> presentCapacity Then
  1243.    Nothing;
  1244.   End
  1245.  Else
  1246.   Begin
  1247.   cursorO := freeHead;
  1248.   cursorP := Ref(freeHead);
  1249.  
  1250.   totalFree := 0;
  1251.   Repeat
  1252.    previousO := cursorO;
  1253.    previousP := cursorP;
  1254.    cursorO := cursorP^.nextFree;
  1255.    cursorP := Ref(cursorO);
  1256.    If cursorO <> freeHead Then
  1257.     totalFree := totalFree + cursorP^.length + BlockRSize;
  1258.    If cursorP^.backFree <> previousO Then
  1259.     Debugger;
  1260.    If cursorP^.nextFree = cursorP^.nextBlock Then
  1261.     Debugger;
  1262.   Until cursorO = freeHead;
  1263.  
  1264.   If Abs(totalFree - (presentCapacity - usedCapacity)) > 0 Then
  1265.    Debugger;
  1266.   End;
  1267.  End;
  1268.  
  1269. Procedure QPool.ChangeBlock (source, destination: BlockO);
  1270.  Var
  1271.   a: Longint;
  1272.  Begin
  1273. {if source <> destination then}
  1274. {for a := 1 to N do}
  1275. {if offsets[a] = source then}
  1276. {begin}
  1277. {offsets[a] := destination;}
  1278. {Leave;}
  1279. {end;}
  1280.  End;
  1281.  
  1282. Procedure QPool.Compact;
  1283.  Var
  1284.   FreeP, PoolP: BlockP;
  1285.   TargetO, StartO, FinishO, NextTargetO, CursorO, NextCursorO: BlockO;
  1286.   TargetP, StartP, FinishP, NextTargetP, CursorP: BlockP;
  1287.   Delta, Length: Longint;
  1288.  
  1289.  Begin
  1290.  FreeP := Ref(freeHead);
  1291.  PoolP := Ref(poolHead);
  1292.  
  1293.  FreeCursor := freeHead;
  1294.  
  1295.  While (FreeP^.nextFree <> freeHead) & (PoolP^.backBlock <> FreeP^.nextFree) Do
  1296.   Begin
  1297.   TargetO := FreeP^.nextFree;
  1298.   TargetP := Ref(TargetO);
  1299.  
  1300.   StartO := TargetP^.nextBlock;
  1301.   StartP := Ref(StartO);
  1302.  
  1303.   NextTargetO := TargetP^.nextFree;
  1304.   If NextTargetO = freeHead Then
  1305.    NextTargetO := poolHead;
  1306.   NextTargetP := Ref(NextTargetO);
  1307.  
  1308.   FinishO := Ref(NextTargetO)^.backBlock;
  1309.   FinishP := Ref(FinishO);
  1310.  
  1311.   CursorO := StartO;
  1312.   CursorP := StartP;
  1313.   Delta := TargetO - StartO;
  1314.   Length := 0;
  1315.   Repeat
  1316.    Length := Length + BlockRSize + CursorP^.length;
  1317.    ChangeBlock(CursorO, CursorO + Delta);
  1318.  
  1319.    CursorP^.backBlock := CursorP^.backBlock + Delta;
  1320.    CursorO := CursorP^.nextBlock;
  1321.    CursorP^.nextBlock := CursorP^.nextBlock + Delta;
  1322.    CursorP := Ref(CursorO);
  1323.   Until CursorO = NextTargetO;
  1324.  
  1325.   CursorO := TargetO + Length;
  1326.   CursorP := Ref(CursorO);
  1327.   StartP^.backBlock := TargetP^.backBlock;
  1328.   FinishP^.nextBlock := CursorO;
  1329.  
  1330.   BlockMove(Ptr(StartP), Ptr(TargetP), Length);
  1331.  
  1332.   CursorP^.length := Abs(Delta);
  1333.   If NextTargetO <> poolHead Then
  1334.    CursorP^.length := CursorP^.length + NextTargetP^.length;
  1335. {BlockRSize added and subtracted to CursorP^.length}
  1336.   CursorP^.free := true;
  1337.  
  1338.   CursorP^.backBlock := FinishO + Delta;
  1339.   CursorP^.backFree := freeHead;
  1340.   FreeP^.nextFree := CursorO;
  1341.  
  1342.   If NextTargetO = poolHead Then
  1343.    Begin
  1344.    CursorP^.nextFree := freeHead;
  1345.    FreeP^.backFree := CursorO;
  1346.  
  1347.    CursorP^.nextBlock := poolHead;
  1348.    PoolP^.backBlock := CursorO;
  1349.    End
  1350.   Else
  1351.    Begin
  1352.    CursorP^.nextFree := NextTargetP^.nextFree;
  1353.    Ref(CursorP^.nextFree)^.backFree := CursorO;
  1354.  
  1355.    CursorP^.nextBlock := NextTargetP^.nextBlock;
  1356.    Ref(CursorP^.nextBlock)^.backBlock := CursorO;
  1357.  
  1358.    FreeCount := FreeCount - 1;
  1359.    End;
  1360.   End;
  1361.  
  1362.  If (PresentCapacity > UsualCapacity) & (FreeP^.backFree = PoolP^.backBlock) Then
  1363.   Begin
  1364.   CursorO := FreeP^.backFree;
  1365.   CursorP := Ref(CursorO);
  1366.  
  1367. {Writeln('Shortening at ', LongintToString(CursorO), '.');}
  1368.  
  1369.   FreeP^.backFree := CursorP^.backFree;
  1370.   Ref(CursorP^.backFree)^.nextFree := freeHead;
  1371.  
  1372.   PoolP^.backBlock := CursorP^.backBlock;
  1373.   Ref(CursorP^.backBlock)^.nextBlock := poolHead;
  1374.  
  1375.   presentCapacity := CursorO;
  1376.   SizeWackyHandle(Pool, PresentCapacity, usesTemporaryMemory);
  1377.  
  1378.   FreeCount := FreeCount - 1;
  1379.   End;
  1380.  
  1381.  End;
  1382.  
  1383. Procedure QuiverTest;
  1384.  Const
  1385.   N = 2500;
  1386.   MinimumLength = 12;
  1387.   MaximumLength = 24;
  1388.  
  1389.   iterationsBeforeReport = 4096;
  1390.  
  1391.  Var
  1392.   offsets: Array[1..N] Of BlockO;
  1393.   sizes: Array[1..N] Of Longint;
  1394.  
  1395.   epoch: Longint;
  1396.  
  1397.   aPool: QPool;
  1398.   a, e, i: Longint;
  1399.   aBlock: BlockO;
  1400.   aBlockP: BlockP;
  1401.   aStringP: StringPtr;
  1402.   anEvent: EventRecord;
  1403.  
  1404.  Begin
  1405.  ShowText;
  1406.  DebugStr('You must uncomment the ChangeBlock method.');
  1407.  
  1408.  For a := 1 To 4 Do
  1409.   randseed := randseed * TickCount * Random;
  1410. {randseed := Longint(-230814419);}
  1411.  Writeln('randseed = ', LongintToString(randseed));
  1412.  Writeln;
  1413.  
  1414.  New(aPool);
  1415.  aPool.Dub('The Pool We Are Testing.');
  1416.  aPool.usesTemporaryMemory := true;
  1417.  aPool.usualCapacity := Trunc(n * (BlockRSize + (minimumLength + maximumLength) / 2));
  1418.  aPool.growthCapacity := 1000;
  1419.  If Not aPool.Construct Then
  1420.   Exit(QuiverTest);
  1421.  
  1422.  i := aPool.usedCapacity;
  1423.  For a := 1 To N Do
  1424.   Begin
  1425.   e := MonteCarlo(MinimumLength, MaximumLength);
  1426.   i := i + e + BlockRSize;
  1427.   If Not aPool.AvailBlock(aBlock, e) Then
  1428.    Debugger;
  1429.   aBlockP := aPool.Ref(aBlock);
  1430.   If aBlockP^.free Then
  1431.    Debugger;
  1432.   aStringP := StringPtr(Clean(aBlockP) + BlockRSize - SizeOfFreeLinks);
  1433.   aStringP^ := LongintToString(Longint(e - SizeOfFreeLinks));
  1434.   offsets[a] := aBlock;
  1435.   sizes[a] := e;
  1436.   If i <> aPool.usedCapacity Then
  1437.    Nothing;
  1438. {aPool.Check;}
  1439.   End;
  1440.  
  1441.  Repeat
  1442.   e := MonteCarlo(1, N);
  1443.  
  1444.   aBlock := offsets[e];
  1445.   aBlockP := aPool.Ref(aBlock);
  1446.  
  1447.   If aBlock <> 0 Then
  1448.    Begin
  1449. {Writeln('Releasing ', LongintToString(aBlock), '.');}
  1450.    aStringP := StringPtr(Clean(aBlockP) + BlockRSize - SizeOfFreeLinks);
  1451.    If aStringP^ <> LongintToString(aBlockP^.length) Then
  1452.     Debugger;
  1453.  
  1454.    aPool.ReleaseBlock(offsets[e]);
  1455.    If offsets[e] <> 0 Then
  1456.     Debugger;
  1457.    sizes[e] := 0;
  1458.    End
  1459.   Else
  1460.    Begin
  1461.    i := MonteCarlo(MinimumLength, MaximumLength);
  1462.    If Not aPool.AvailBlock(offsets[e], i) Then
  1463.     If Not aPool.AvailBlock(offsets[e], i) Then
  1464.      Debugger;
  1465. {Writeln('Created ', LongintToString(offsets[e]), '.');}
  1466.    If offsets[e] = 0 Then
  1467.     Debugger;
  1468.    aBlockP := aPool.Ref(offsets[e]);
  1469.    aStringP := StringPtr(Clean(aBlockP) + BlockRSize - SizeOfFreeLinks);
  1470.    aStringP^ := LongintToString(Longint(i - SizeOfFreeLinks));
  1471.    sizes[e] := i;
  1472.    End;
  1473.  
  1474. {aPool.Check;}
  1475. {Writeln;}
  1476.  
  1477.   GetKeys;
  1478.  
  1479.   epoch := epoch + 1;
  1480.   If epoch > iterationsBeforeReport Then
  1481.    Begin
  1482. {If Button Then}
  1483.    Begin
  1484.    Write('CompactingI ');
  1485.    aPool.usualCapacity := aPool.usedCapacity;
  1486.    aPool.Compact;
  1487.    Write('Done. ');
  1488.    End;
  1489.  
  1490.    Writeln(PercentageToString(Percentage(aPool.usedCapacity, aPool.presentCapacity)), ' used.');
  1491. {aPool.Check;}
  1492.    epoch := 0;
  1493.  
  1494.    SystemTask;
  1495.    aPool.Loosen;
  1496.    If WaitNextEvent(everyEvent, anEvent, 3000, Nil) Then
  1497.     Nothing;
  1498.    aPool.Fasten;
  1499.    End;
  1500.  
  1501.   If epoch Mod (iterationsBeforeReport Div 4) = 0 Then
  1502.    Begin
  1503.    aPool.Loosen;
  1504.    If WaitNextEvent(everyEvent, anEvent, 0, Nil) Then
  1505.     Nothing;
  1506.    aPool.Fasten;
  1507.    End;
  1508.  
  1509.  Until SpaceKey;
  1510.  
  1511.  aPool.Destruct;
  1512.  End;
  1513.  
  1514. End.
  1515.  
  1516. ---------------------------
  1517.  
  1518. End of C.S.M.P. Digest
  1519. **********************
  1520.